package com.wectrls.common.functionalInterface;

import com.wectrls.config.exceptiom.CommonException;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author chenjian
 * @Package
 * @Description:
 * @date 2019/7/4 10:14
 */
@Slf4j
public class FieldNameUtils {

    /**
     * 缓存类-Lambda的映射关系
     */
    private static Map<Class, SerializedLambda> classCache = new ConcurrentHashMap<>();

    private static final String set = "set";
    private static final String get = "get";
    private static final String is = "is";

    /**
     * 清空缓存,可以配合定时器一起使用
     */
    public static void cacheClear() {
        classCache.clear();
    }

    /***
     * 转换方法引用为属性名
     * @param fn
     * @return
     */
    public static <T> String convertToFieldName(IGetter<T> fn) {
        SerializedLambda lambda = getSerializedLambda(fn);
        String mName = lambda.getImplMethodName();

        String prefix = null;
        if (mName.startsWith(get)) {
            prefix = get;
        } else if (mName.startsWith(is)) {
            prefix = is;
        } else {
            log.error("无效的getter方法:{} ", mName);
            throw new RuntimeException("服务器内部错误,使用了无效的getter方法::" + mName);
        }
        return substringAfterAndUncapFirst(mName, prefix);
    }

    private static String substringAfterAndUncapFirst(String str, String pre) {
        boolean startsWith = str.startsWith(pre);
        int sL = str.length();
        int pL = pre.length();
        if (startsWith && sL > pL) {
            //切除
            String s = str.substring(pL);
            return String.valueOf(s.charAt(0)).toLowerCase() + s.substring(1);
        }
        throw new CommonException("字段转换异常", 5000);
    }

    /***
     * 转换setter方法引用为属性名
     * @param fn
     * @return
     */
    private static <T, R> String convertToFieldName(ISetter<T, R> fn) {
        SerializedLambda lambda = getSerializedLambda(fn);
        String methodName = lambda.getImplMethodName();
        if (!methodName.startsWith(set)) {
            log.warn("无效的setter方法: " + methodName);
        }
        // 截取set之后的字符串并转换首字母为小写（
        return substringAfterAndUncapFirst(methodName, set);
    }

    /***
     * Java反射效率较低，采用内存缓存部分数据可以提高转换效率
     *
     * 控制缓存大小，防止缓存数据过大导致内存溢出
     *
     * @param fn
     * @return
     */
    private static SerializedLambda getSerializedLambda(Serializable fn) {
        //先检查缓存中是否已存在
        SerializedLambda lambda = classCache.get(fn.getClass());
        if (null == lambda) {
            try {//提取SerializedLambda并缓存
                Method method = fn.getClass().getDeclaredMethod("writeReplace");
                method.setAccessible(Boolean.TRUE);
                lambda = (SerializedLambda) method.invoke(fn);
                classCache.put(fn.getClass(), lambda);
            } catch (Exception e) {
                log.error("获取SerializedLambda异常, class={}", fn.getClass().getSimpleName());
                e.printStackTrace();
            }
        }
        return lambda;
    }
}
